package com.google.code.p.restrpc.spring.assmebler;

import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

import com.google.code.p.restrpc.core.RpcServiceException;
import com.google.code.p.restrpc.core.RpcServiceMetadata;
import com.google.code.p.restrpc.spring.metadata.AnnotationRpcAttributeSource;
import com.google.code.p.restrpc.spring.metadata.RpcAttributeSource;
import com.google.code.p.restrpc.spring.metadata.RpcMetadata;
import com.google.code.p.restrpc.spring.naming.MetadataNamingStrategy;

public class RpcServiceInfoMetadataAssembler implements
                                            AutodetectCapableRpcServiceInfoAssembler,
                                            InitializingBean {
    
    private RpcAttributeSource attributeSource;
    
    private MetadataNamingStrategy metadataNamingStrategy;
    
    public RpcServiceInfoMetadataAssembler() {
        this.attributeSource = new AnnotationRpcAttributeSource();
        this.metadataNamingStrategy = new MetadataNamingStrategy(attributeSource);
    }
    
    public void setAttributeSource(RpcAttributeSource attributeSource) {
        Assert.notNull(attributeSource, "RpcAttributeSource must not be null");
        this.attributeSource = attributeSource;
        this.metadataNamingStrategy.setAttributeSource(attributeSource);
    }
    
    protected void checkRpcService(Object bean) throws IllegalArgumentException {
        if (AopUtils.isJdkDynamicProxy(bean)) {
            throw new IllegalArgumentException("RpcServiceInfoMetadataAssembler does not support JDK dynamic proxies - export the target beans directly or use CGLIB proxies instead");
        }
    }
    
    public boolean includeBean(Object bean, String beanName) {
        return (this.attributeSource.getRpcMetadata(AopUtils.getTargetClass(bean)) != null);
    }
    
    public RpcServiceMetadata getRemoteServiceInfo(Object bean, String beanName) throws RpcServiceException {
        checkRpcService(bean);
        Class serviceClass = AopUtils.getTargetClass(bean);
        RpcMetadata metadata = attributeSource.getRpcMetadata(serviceClass);
        RpcServiceMetadata result = new RpcServiceMetadata();
        result.setService(bean);
        result.setServiceName(metadataNamingStrategy.getServiceName(bean,
                                                                    beanName));
        result.setDescription(metadata.getDescription());
        result.setServiceInterfaces(serviceClass.getInterfaces());
        return result;
    }
    
    public void afterPropertiesSet() {
        Assert.notNull(attributeSource, "RpcAttributeSource must not be null");
    }
    
}
